﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMStudio.Common;
using System.Text.RegularExpressions;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using AMStudio.DelegateDispather;
using System.IO.Ports;
using System.Threading;

namespace AMStudio.Driver
{
    public class LmiCameraDriver : IAutomationDriver
    {
        private int intBeginRead = 0;
        protected ExceptionManager ExManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

        private LmiCameraConfig myConfig = null;

        private DelegateDispather.IEventClient eventClient;
        public DelegateDispather.IEventClient EventClient
        {
            get { return eventClient; }
            set { eventClient = value; }
        }
        private LmiCamera hardwaredriver;
        private bool alreadyinitialized = false;
        private IExecuteReader result = new ExecuteReader(false);

        private string CurrentJob = string.Empty;
        private String hardwareName = "CAMERA";
        public String HardwareName
        {
            get { return hardwareName; }
            set { hardwareName = value; }
        }
        private String hardwareEvent = "CAMERA_RET";
        public String HardwareEvent
        {
            get { return hardwareEvent; }
            set { hardwareEvent = value; }
        }

        public void Initialize(IEventManager eventManager, LmiCameraConfig config)
        {
            myConfig = config;
            hardwaredriver = new LmiCamera(config.IPAddress, config.TcpPort, config.User, config.Password);
            hardwaredriver.OnDataReceived += new LmiCamera.CameraDataReceivedHandler(hardwaredriver_OnDataReceived);
            hardwaredriver.OnConnectClosed += new LmiCamera.CameraConnectClosedHandler(hardwaredriver_OnConnectClosed);
            hardwaredriver.OnConnected += new LmiCamera.CameraConnectedHandler(hardwaredriver_OnConnected);
            eventClient = new EventClient(eventManager);
            this.hardwareEvent = config.HardwareEvent;
            this.hardwareName = config.HardwareName;
        }
        public virtual int ExecuteNonQuery(string command, params object[] parameters)
        {
            return -1;
        }
        public virtual IExecuteReader ExecuteReader(string command, params object[] parameters)
        {
            //_Signal_Command_Finished.Reset();
            _Received_Data = null;
            result.Success = false;
            try
            {
                switch (command)
                {
                    case "INIT":
                        #region Command "INIT"
                        {
                            if (!alreadyinitialized)
                            {
                                this.Initialize((IEventManager)parameters[0], (LmiCameraConfig)parameters[1]);
                                if (!hardwaredriver.Initialize())
                                {
                                    Logger.Write("System Error! (Can not connect the laser controller!)");
                                    hardwaredriver.Close();
                                }
                                else
                                {
                                    result.Success = true;
                                    alreadyinitialized = true;
                                }
                            }
                        }
                        #endregion
                        break;
                    case "EXIT":
                        #region Command "DISCONNECT"
                        result.Success = true;
                        if (alreadyinitialized)
                        {
                            hardwaredriver.Close();
                            alreadyinitialized = false;
                        }
                        #endregion
                        break;
                    case "TRIGGER":
                        #region Command "TRIGGER"
                        {
                            _Current_Command = "TRIGGER";
                            string product_code = parameters[0].ToString();
                            intBeginRead = 0;
                            _Received_Data = null;
                            result.Success = false;
                            _Signal_Command_Finished.Reset();

                            if (alreadyinitialized)
                            {
                                string str = string.Empty;
                                intBeginRead = Environment.TickCount & Int32.MaxValue;
                                result.Success = hardwaredriver.SendCommand("sttest" + product_code + "en", string.Empty);
                            }
                        }
                        #endregion
                        break;
                    case "TRIGGER_STATUS":
                        #region Command "MARKING_STATUS"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "TRIGGER_STATUS";

                                if (_Signal_Command_Finished.WaitOne(1,false ))
                                {
                                    result.Success = true;

                                    if (_2DCode == "stpaoken")
                                    {
                                        result.Result = true;
                                    }
                                    else
                                    {
                                        result.Result = false;
                                    }
                                }
                                else
                                {

                                    int intTickCount = Environment.TickCount & Int32.MaxValue;

                                    int intTimeTaken = intTickCount < intBeginRead ? Int32.MaxValue - intBeginRead + intTickCount : intTickCount - intBeginRead;
                                    
                                    
                                    if (intTimeTaken > 3000)
                                    {
                                        result.Success = true;
                                        result.Result = false.ToString();
                                    }
                                    else
                                    {
                                        result.Success = false;
                                        result.Result = false.ToString();
                                    }
                                }
                            }
                            else
                            {
                                result.Success = true;
                                result.Result = string.Empty;
                            }                            
                        }
                        #endregion
                        break;
                    case "CONNECT_STATUS":
                        #region Command "CONNECT_STATUS"
                        {
                            if (alreadyinitialized)
                            {
                                result.Result = true;
                                result.Success = true;
                            }
                            else
                            {
                                result.Result = false;
                                result.Success = true;
                            }

                        }
                        #endregion
                        break;
                    case "SET_FILE":
                        #region Command "SET_FILE"
                        {
                            _Current_Command = "SET_FILE";
                            string program_id = parameters[0].ToString();
                            result.Success = false;
                            _Signal_Command_Finished.Reset();

                            if (alreadyinitialized)
                            {
                                if (hardwaredriver.SendCommand("stchan" + program_id + "en", string.Empty))
                                {
                                    if (_Signal_Command_Finished.WaitOne(2000, false))
                                    {
                                        if (_2DCode == "stchoken")
                                        {
                                            result.Success = true;
                                            result.Result = parameters[0];
                                        }
                                    }
                                }
                            }
                        }
                        #endregion
                        break;
                    case "GET_FILENAME":
                        #region Command "GET_FILENAME"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "GET_FILENAME";
                                result.Success = true;
                                result.Result = CurrentJob;
                                RaiseEvent("GET_FILENAME", true, result.Result);
                            }
                        }
                        #endregion
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                ExManager.HandleException(ex, "Policy");
                alreadyinitialized = false;
                RaiseEvent("DISCONNECT", true, null);
                if (hardwaredriver != null)
                    hardwaredriver.Close();
            }
            return result;
        }



        private void hardwaredriver_OnConnected(object sender, EventArgs e)
        {
            RaiseEvent("CONNECTED", true, null);
        }

        private void hardwaredriver_OnConnectClosed(object sender, EventArgs e)
        {
            alreadyinitialized = false;

            RaiseEvent("DISCONNECTED", true, null);
        }

        private void hardwaredriver_OnDataReceived(object sender, CameraArgs e)
        {
            _2DCode = e.ReceivedString;
            _Signal_Command_Finished.Set();
            RaiseEvent("DATA_RECEIVE", true, _2DCode);
        }

        #region Variable, common for each hardware, hardware related

        private AutoResetEvent _Signal_Command_Finished = new AutoResetEvent(false);
        private string[] _Received_Data = null;
        private String _Current_Command = String.Empty;
        private String _Current_Tag = string.Empty;
        private bool _CameraRequest_Result = false;
        private string _2DCode = string.Empty;
        #endregion

        public void RaiseEvent(string command, bool status, object result)
        {
            StationEventArgs arg = new StationEventArgs(hardwareName, command, status, result);
            eventClient.RaiseEvent(hardwareEvent, arg);
        }
    }
}
